#include <limits.h>
#include <float.h>
#include "viaimg.h"
using namespace nVIA;

TCHAR*	CBitmap::m_formatNames[COLOR_FORMAT_NUM] = {
	"BYTE",
	"BGR",
	"RGB",
	"YUV",
	"WORD",
	"DWORD",
	"FLOAT",
	"DOUBLE"
};

BOOL	nVIA::CBitmap::Init(int width, int height, ColorFormat format, BOOL align)
{
	int y;
	PBYTE pd, ps;

	if (width <= 0 || height <= 0)
		return FALSE;

	m_width = width;
	m_height = height;
	m_format = format;
	m_isAlign = align;
	m_bufferPitch = getBufferPitchFromFormat();

	if (m_bufSize < m_height * m_bufferPitch) {
		if (m_buffer)
			delete [] m_buffer;
		m_buffer = new BYTE[m_height * m_bufferPitch];
		m_bufSize = m_height * m_bufferPitch;
	}

	m_pitch = ALIGN4(m_width * 3);
	if (m_bitsSize < m_height * m_pitch) {
		if (m_bits)
			delete [] m_bits;
		m_bits = new BYTE[m_height * m_pitch];
		m_bitsSize = m_height * m_pitch;
	}
	memset(m_bits, 0, m_height * m_pitch);

// 	switch (format) {
// 	case ColorFormat_BGR:
// 		pd = m_buffer;
// 		ps = bits;
// 		for (y = 0; y < height; y++) { 
// 			memcpy(pd, ps, width * 3);
// 			pd += m_bufferPitch;
// 			ps += pitch;
// 		}
// 		break;
// 	default:
// 		return FALSE;
// 	}

	memset(&m_biInfo, 0, sizeof(m_biInfo));
	m_biInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	m_biInfo.bmiHeader.biWidth = m_width;
	m_biInfo.bmiHeader.biHeight = m_height;
	m_biInfo.bmiHeader.biPlanes = 1;
	m_biInfo.bmiHeader.biBitCount = 24;
	
	return TRUE;
}

void	nVIA::CBitmap::Release()
{
	if (m_buffer) {
		delete [] m_buffer;
		m_buffer = NULL;
	}
	if (m_bits) {
		delete [] m_bits;
		m_bits = NULL;
	}
	m_bitsSize = 0;
	m_bufSize = 0;
}

BOOL	nVIA::CBitmap::Update()
{
	BYTE* pd = m_bits;
	int x, y;

	switch (m_format) {
		case ColorFormat_BYTE:
			{
				BYTE* ps = m_buffer;
				for (y = 0; y < m_height; y++) {
					for (x = 0; x < m_width; x++) {
						pd[0] = *ps;
						pd[1] = *ps;
						pd[2] = *ps;

						ps++;
						pd += 3;
					}
					ps += m_bufferPitch - m_width;
					pd += m_pitch - 3 * m_width;
				}
				return TRUE;
			}
			break;

		case ColorFormat_BGR:
			{
				BYTE* ps = m_buffer;
				
				if (m_bufferPitch == m_pitch) {
					memcpy(m_bits, m_buffer, m_height * m_pitch);
					return TRUE;
				}

				for (y = 0; y < m_height; y++) {
					memcpy(pd, ps, m_width * 3);
					ps += m_bufferPitch;
					pd += m_pitch;
				}
				return TRUE;
			}

			break;

		case ColorFormat_RGB:
			{
				BYTE* ps = m_buffer;
				for (y = 0; y < m_height; y++) {
					for (x = 0; x < m_width; x++) {
						pd[0] = ps[2];
						pd[1] = ps[1];
						pd[2] = ps[0];
						ps += 3;
						pd += 3;
					}
					ps += m_bufferPitch - 3 * m_width;
					pd += m_pitch - 3 * m_width;
				}
				return TRUE;
			}
			break;

		case ColorFormat_YUV:
			break;

		case ColorFormat_WORD:
			{
				WORD* ps = (WORD*)m_buffer;
				int minV = SHRT_MAX, maxV = SHRT_MIN;
				for (y = 0; y < m_height; y++) {
					for (x = 0; x < m_width; x++) {
						WORD v = *ps++;
						if (v > maxV)
							maxV = v;
						else if (v < minV)
							minV = v;
					}
					ps = (WORD*) ((BYTE*) ps + m_bufferPitch - m_width * sizeof(WORD));
				}
				ps = (WORD*) m_buffer;
				assert(maxV >= minV);
				if (maxV == minV) {
					memset(m_bits, maxV, m_height * m_pitch);
					return TRUE;
				}
				for (y = 0; y < m_height; y++) {
					for (x = 0; x < m_width; x++) {
						int v = ((*ps++) - minV) * 255 / (maxV - minV);
						pd[0] = v;
						pd[1] = v;
						pd[2] = v;

						pd += 3;
					}
					ps = (WORD*) ((BYTE*) ps + m_bufferPitch - m_width * sizeof(WORD));
					pd += m_pitch - 3 * m_width;
				}
				return TRUE;
			}
			break;

		case ColorFormat_DWORD:
			{
				DWORD* ps = (DWORD*) m_buffer;
				int minV = INT_MAX, maxV = INT_MIN;
				for (y = 0; y < m_height; y++) {
					for (x = 0; x < m_width; x++) {
						DWORD v = *ps++;
						if (v > maxV)
							maxV = v;
						else if (v < minV)
							minV = v;
					}
					ps = (DWORD*) ((BYTE*) ps + m_bufferPitch - m_width * sizeof(DWORD));
				}
				ps = (DWORD*) m_buffer;
				assert(maxV >= minV);
				if (maxV == minV) {
					memset(m_bits, maxV, m_height * m_pitch);
					return TRUE;
				}
				for (y = 0; y < m_height; y++) {
					for (x = 0; x < m_width; x++) {
						int v = ((*ps++) - minV) * 255 / (maxV - minV);
						pd[0] = v;
						pd[1] = v;
						pd[2] = v;

						pd += 3;
					}
					ps = (DWORD*) ((BYTE*) ps + m_bufferPitch - m_width * sizeof(DWORD));
					pd += m_pitch - 3 * m_width;
				}
				return TRUE;
			}
			break;

		case ColorFormat_FLOAT:
			break;

		case ColorFormat_DOUBLE:
			break;
		default:
			assert(0);
	}

	return FALSE;
}